
#include <vector>
#include "scene.h"
#include "configurable.h"
#include "camera.h"
#include "polygonRT.h"
#include "configurator.h"
#include "solid_loader.h"
#include "studio.h"
using namespace std;
DLL_EXPORTED(int) Tfoo(int a)
{
	return a+1;
}
typedef gemren::studio studio;
vector<studio> studios;
studio& getscene(scene_handle hnd)
{
	return studios[hnd];
}
struct image_parse_data
{
	unsigned int* img;
	studio* s;
};
void parse_line(size_t tid, void* ptr, size_t elt)
{ //parsing to integer RGB - single thread
	image_parse_data* d = (image_parse_data*) ptr;
	const int w = d->s->width,
			  h = d->s->height;
	embree::Col3f* fimg = d->s->img;
	unsigned int* img = d->img;
	float range = std::pow(2,d->s->exposition);
	unsigned int* ipos = img + (elt*w);
	embree::Col3f* fpos = fimg + (elt*w);
	for(int i = 0; i<w; ++i)
	{
		embree::Col3f col(255.0f*embree::sqrt(embree::clamp(range* (*fpos))));
		*ipos = ((unsigned char)col.r << 16) + ((unsigned char)col.g << 8) + (unsigned char)col.b;
		++ipos; ++fpos;
	}
}
DLL_EXPORTED(void) RTgetImg(scene_handle sh, unsigned int* img)
{
	studio& s(getscene(sh));
	image_parse_data ipd = { img, &s };

	embree::scheduler->addTask(parse_line, &ipd, s.height);
	embree::scheduler->go();
}
DLL_EXPORTED(scene_handle) RTcreateScene(char file[])
{
	if(studios.size() == 0)
	{//add dummy instead of 0th scene (0 = error)
		studios.push_back(studio(0));
	}
	try
	{
		studios.push_back( gemren::solid_loader::load_scene(file));
	}
	catch(...)
	{
		return 0;
	}
	return studios.size()-1;
}
DLL_EXPORTED(void) RTfreeScene(scene_handle hnd)
{
	getscene(hnd).clean();
}

DLL_EXPORTED(void) RTsetDim(scene_handle scene, int width, int height)
{
	studio& s = getscene(scene);
	s.setdim(width, height);
}
DLL_EXPORTED(void) RTsetCam(scene_handle scene, 
	double cx,double cy,double cz,
	double dx,double dy,double dz)
{
	studio& s = getscene(scene);
	if(!s.cam)
	{
		s.cam = new gemren::camera(s.thescene);
	}
	s.cam->set_FOV(90.0f);
	s.cam->set_view(gemren::coord(float(cx),float(cy),float(cz)),gemren::coord(float(dx),float(dy),float(dz)));
	s.spp = 0;
}
DLL_EXPORTED(void) RTcameraDirDelta(scene_handle hnd, float dx, float dy, float* newdir)
{   //returns updated direction in <newdir>
	studio& s = getscene(hnd);
	s.cam->dir_delta(dx, dy, newdir);
	s.spp = 0;
}
DLL_EXPORTED(void) RTcameraPosDelta(scene_handle hnd, float dx, float dy, float dz, float* newpos)
{   //returns updated position in <newpos>
	studio& s = getscene(hnd);
	s.cam->pos_delta(dx, dy, dz, newpos);
	s.spp = 0;
}

DLL_EXPORTED(int) RTshootImage(scene_handle hscene, bool fast)//, int l, int t, int r, int b)
{
	studio& sc(getscene(hscene));
	if(sc.height>0 && sc.width>0)
	{
		sc.prepare_shot();
		sc.cam->snap(sc.img, sc.width, sc.height, sc.spp, fast);
		return ++sc.spp;
	}
	return 0;
}

DLL_EXPORTED(void) RTgetResolution(scene_handle hnd, int* arr)
{
	getscene(hnd).getdim(arr[0], arr[1]);
}

DLL_EXPORTED(int) RTsetInt(scene_handle hnd, char* name, int value)
{
	std::string sname(name);
	gemren::err_t ret = getscene(hnd).set_int(sname, value);
	if(ret == gemren::ERR_OK) getscene(hnd).spp = 0;
	if(ret == gemren::ERR_OK_NOSCRATCH) ret = gemren::ERR_OK;
	return ret;
}
DLL_EXPORTED(int) RTsetString(scene_handle hnd, char* name, char* value)
{
	std::string sname(name);
	gemren::err_t ret = getscene(hnd).set_string(sname, value);
	if(ret == gemren::ERR_OK) getscene(hnd).spp = 0;
	if(ret == gemren::ERR_OK_NOSCRATCH) ret = gemren::ERR_OK;
	return ret;
}
DLL_EXPORTED(int) RTsetFloat(scene_handle hnd, char* name, float value)
{
	std::string sname(name);
	gemren::err_t ret = getscene(hnd).set_float(sname, value);
	if(ret == gemren::ERR_OK) getscene(hnd).spp = 0;
	if(ret == gemren::ERR_OK_NOSCRATCH) ret = gemren::ERR_OK;
	return ret;
}
DLL_EXPORTED(int) RTsetBool(scene_handle hnd, char* name, bool value)
{
	std::string sname(name);
	gemren::err_t ret = getscene(hnd).set_bool(sname, value);
	if(ret == gemren::ERR_OK) getscene(hnd).spp = 0;
	if(ret == gemren::ERR_OK_NOSCRATCH) ret = gemren::ERR_OK;
	return ret;
}
DLL_EXPORTED(void) RTannounceProperties(scene_handle hnd, property_announcer announcer)
{
	getscene(hnd).announce_properties("", announcer);
}




DLL_EXPORTED(int) RTsaveImage(scene_handle hnd, char *filename)
{
	return getscene(hnd).save_image(filename);
}

DLL_EXPORTED(void) RTonscreenMaterialName(scene_handle hnd, int x, int y, char** sp)
{
	gemren::studio s = getscene(hnd);
	*sp = (char*) s.cam->get_onscreen_material_name(x,y, s.width, s.height).c_str();
}